package cpabe;

import BlockR.Encrypt;
import BlockR.model.RandomNumOBJ;
import it.unisa.dia.gas.jpbc.Element;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;

import cpabe.policy.LangPolicy;
import bswabe.Bswabe;
import bswabe.BswabeCph;
import bswabe.BswabeCphKey;
import bswabe.BswabeElementBoolean;
import bswabe.BswabeMsk;
import bswabe.BswabePrv;
import bswabe.BswabePub;
import bswabe.SerializeUtils;
import Demo.DemoForCpabe;

public class Cpabe {

    /**
     * @param pubfile
     * @param mskfile
     * @author Junwei Wang(wakemecn@gmail.com)
     */
    public static byte[][][] brBuf;

    public void setup(String pubfile, String mskfile) throws IOException,
            ClassNotFoundException {
        byte[] pub_byte, msk_byte;
        BswabePub pub = new BswabePub();
        BswabeMsk msk = new BswabeMsk();
        Bswabe.setup(pub, msk);

        /* store BswabePub into mskfile */
        pub_byte = SerializeUtils.serializeBswabePub(pub);
        Common.spitFile(pubfile, pub_byte);

        /* store BswabeMsk into mskfile */
        msk_byte = SerializeUtils.serializeBswabeMsk(msk);
        Common.spitFile(mskfile, msk_byte);
    }

    public void keygen(String pubfile, String prvfile, String mskfile,
                       String attr_str) throws NoSuchAlgorithmException, IOException {
        BswabePub pub;
        BswabeMsk msk;
        byte[] pub_byte, msk_byte, prv_byte;

        /* get BswabePub from pubfile */
        pub_byte = Common.suckFile(pubfile);
        pub = SerializeUtils.unserializeBswabePub(pub_byte);

        /* get BswabeMsk from mskfile */
        msk_byte = Common.suckFile(mskfile);
        msk = SerializeUtils.unserializeBswabeMsk(pub, msk_byte);

        String[] attr_arr = LangPolicy.parseAttribute(attr_str);
        BswabePrv prv = Bswabe.keygen(pub, msk, attr_arr);

        /* store BswabePrv into prvfile */
        prv_byte = SerializeUtils.serializeBswabePrv(prv);
        Common.spitFile(prvfile, prv_byte);
    }

    public void enc(String pubfile, String policy, String inputfile,
                    String encfile) throws Exception {
        BswabePub pub;
        BswabeCph cph;
        BswabeCphKey keyCph;
//        byte[] plt;
        byte[] cphBuf;
//        byte[] aesBuf;
        byte[] pub_byte;
        Element m;

        /* get BswabePub from pubfile */
        pub_byte = Common.suckFile(pubfile);
        pub = SerializeUtils.unserializeBswabePub(pub_byte);

        keyCph = Bswabe.enc(pub, policy);
        cph = keyCph.cph;
        m = keyCph.key;
        System.err.println("m = " + m.toString());

        if (cph == null) {
            System.out.println("Error happed in enc");
            System.exit(0);
        }
        cphBuf = SerializeUtils.bswabeCphSerialize(cph);
        /* read file to encrypted plt是原本代码中的需要加密的明文*/
//        plt = Common.suckFile(inputfile);
//        aesBuf = AESCoder.encrypt(m.toBytes(), plt);
        /*得到并存储原文Block-R算法加密后的密文 encfile*/
        brBuf = BlockR.Encrypt.encrypt(inputfile, m);
        BlockR.function.Output.output(encfile, brBuf);
        /*存储Block-R算法需要的秘钥原文 brKeyFile1 brKeyFile2*/
        Common.spitFile(DemoForCpabe.brKeyFile1, Encrypt.firstBlockKey.getR1());
        Common.spitFile(DemoForCpabe.brKeyFile2, Encrypt.firstBlockKey.getR2());
        /*存储属性信息密文 encCphFile*/
        Common.spitFile(DemoForCpabe.encCphFile, cphBuf);
//        Common.writeCpabeFile(encfile, cphBuf, aesBuf);
    }

    public void dec(String pubfile, String prvfile, String encfile,
                    String decfile) throws Exception {
//        byte[] aesBuf;
        byte[] cphBuf;
//        byte[] plt;
        byte[] prv_byte;
        byte[] pub_byte;
//        byte[][] tmp;
        BswabeCph cph;
        BswabePrv prv;
        BswabePub pub;
        /* get BswabePub from pubfile */
        pub_byte = Common.suckFile(pubfile);
        pub = SerializeUtils.unserializeBswabePub(pub_byte);

        /* read ciphertext */
        /*tmp = Common.readCpabeFile(encfile);
        aesBuf = tmp[0];
        cphBuf = tmp[1];*/

        /*读取brKeyFile1 brKeyFile2 获得Block-R算法需要的秘钥原文*/
        byte[] brKeyR1 = Common.suckFile(DemoForCpabe.brKeyFile1);
        byte[] brKeyR2 = Common.suckFile(DemoForCpabe.brKeyFile2);
        RandomNumOBJ firstBlockKey = new RandomNumOBJ(brKeyR1, brKeyR2);
        /*读取属性属性信息密文*/
        cphBuf = Common.suckFile(DemoForCpabe.encCphFile);
        cph = SerializeUtils.bswabeCphUnserialize(pub, cphBuf);

        /* get BswabePrv form prvfile */
        prv_byte = Common.suckFile(prvfile);
        prv = SerializeUtils.unserializeBswabePrv(pub, prv_byte);

        BswabeElementBoolean beb = Bswabe.dec(pub, prv, cph);
        System.err.println("e = " + beb.e.toString());
        if (beb.b) {
//            plt = AESCoder.decrypt(beb.e.toBytes(), aesBuf);
//            Common.spitFile(decfile, plt);
            /*校验属性通过后解密原文*/
            brBuf = BlockR.Decrypt.decrypt(encfile, DemoForCpabe.arraySize, firstBlockKey);
            BlockR.function.Output.outputContent(decfile, brBuf);
        } else {
            System.exit(0);
        }


    }

}
